package composite;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;

import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Composite pattern - group object.
 * Defines group object, which can hold another object or group of objects.
 * It basically runs all given methods on all child and allows to add and remove child.
 * Primitive objects are in the interpreter package.
 */
@SuppressWarnings("serial")
public class ObjectGroup implements ObjectItem{	
	/** Optional name */
    private String name;
    
    private double scaleX = 1;
    private double scaleY = 1;
    public double getScaleX() { return scaleX; }
	public double getScaleY() {	return scaleY; }
	
	/** List of child objects, accessed through the interface */
    private ArrayList<ObjectItem> objectItems = new ArrayList<ObjectItem>();
    
    boolean isSelected = false;
    
	/** Constructors */
	public ObjectGroup(){}
    public ObjectGroup(String newName){
        name = newName;
    }    
    
    /**
     * Run the draw method for all child
     */
    public void drawObject(Graphics g){
        Iterator<ObjectItem> items = objectItems.iterator();
        while(items.hasNext()){
            ObjectItem item = (ObjectItem)items.next();
            item.drawObject(g);
        }
        
        if(isSelected)
        	drawHighlightSquares(g);
    }
    
    /**
     * Run the move method for all child
     */
	public void moveObject(int posX, int posY){
        Iterator<ObjectItem> items = objectItems.iterator();
        while(items.hasNext()){
            ObjectItem item = (ObjectItem)items.next();
            item.moveObject(posX, posY);
        }
	}
		
	/**
	 * Find the surrounding rectangle for whole group of objects.
	 * It is a bit tricky.
	 */
	public Rectangle2D getBoundsRectangle(){
		//Initial values for search, "2000" is never possible max x and y to cut off from.
		double x=2000, y=2000, w=0, h=0;
		
		// Find the one, all child surrounding rectangle.
        Iterator<ObjectItem> items = objectItems.iterator();
        while(items.hasNext()){
            ObjectItem item = (ObjectItem)items.next();
    
            Rectangle2D itemRec = item.getBoundsRectangle();        
            if(itemRec.getX() < x){
            	double deltaX = x - itemRec.getX();            
            	if(x != 2000)
            		w += deltaX; 
            	
            	x = itemRec.getX();
            }
            if(itemRec.getY() < y){
            	double deltaY = y - itemRec.getY();            
            	if(y != 2000)
            		h += deltaY; 
            	
            	y = itemRec.getY();
            }
            if(itemRec.getMaxX() -x > w)
            	w = itemRec.getMaxX() -x;       
            if(itemRec.getMaxY() -y > h)
            	h = itemRec.getMaxY() -y;
        }
		
        Rectangle2D highlightRec = new Rectangle.Double(x,y,w,h);
        return highlightRec;
	}
	/** Selected squares around the shape */
    public void drawHighlightSquares(Graphics g) {
    	Graphics2D g2D = (Graphics2D) g;
    	
    	Rectangle2D r = getBoundsRectangle();
		double x = r.getX() -15;
        double y = r.getY() - 15;
        double w = r.getWidth() + 30;
        double h = r.getHeight() + 30;

        g2D.setColor(Color.black);

        g2D.fill(new Rectangle.Double(x - 3.0, y - 3.0, 6.0, 6.0));
        g2D.fill(new Rectangle.Double(x + w * 0.5 - 3.0, y - 3.0, 6.0, 6.0));
        g2D.fill(new Rectangle.Double(x + w - 3.0, y - 3.0, 6.0, 6.0));
        g2D.fill(new Rectangle.Double(x - 3.0, y + h * 0.5 - 3.0, 6.0, 6.0));
        g2D.fill(new Rectangle.Double(x + w - 3.0, y + h * 0.5 - 3.0, 6.0, 6.0));
        g2D.fill(new Rectangle.Double(x - 3.0, y + h - 3.0, 6.0, 6.0));
        g2D.fill(new Rectangle.Double(x + w * 0.5 - 3.0, y + h - 3.0, 6.0, 6.0));
        g2D.fill(new Rectangle.Double(x + w - 3.0, y + h - 3.0, 6.0, 6.0));      
      }
	
	/**
	 * Create a copy of the group object item(and all child), 
	 * to avoid references issues for not base(?)(int etc.) types
	 */
	public ObjectItem clone(){
		ObjectGroup groupCopy = new ObjectGroup(name);
		
        Iterator<ObjectItem> items = objectItems.iterator();
        while(items.hasNext()){
            ObjectItem item = (ObjectItem)items.next();
            groupCopy.addObjectItem(item.clone());
        }
		return groupCopy;
	}
	
	/**
	 * Set color for all child
	 */
	public void setColor(Color color){
        Iterator<ObjectItem> items = objectItems.iterator();
        while(items.hasNext()){
            ObjectItem item = (ObjectItem)items.next();
            item.setColor(color);
        }
    }
	
	public Color getColor(){
        Iterator<ObjectItem> items = objectItems.iterator();
        while(items.hasNext()){
            ObjectItem item = (ObjectItem)items.next();
            return item.getColor();
        }
		return null;//it should be never returned
	}
	
	/**
	 * Scale all child
	 */
	public void scale(double scaleX , double scaleY){
		// Store scale variables of the group
		this.scaleX = scaleX;
		this.scaleY = scaleY;
		// Set scale of child
        Iterator<ObjectItem> items = objectItems.iterator();
        while(items.hasNext()){
            ObjectItem item = (ObjectItem)items.next();
            item.scale(scaleX, scaleY);
        }
	}
		
	/** Add new child */
    public void addObjectItem(ObjectItem element){
        if (!objectItems.contains(element)){
            objectItems.add(element);
        }
    }
    
    /** Remove child */
    public void removeObjectItem(ObjectItem element){
        objectItems.remove(element);
    }    
    
    public boolean isSelected() {
		return isSelected;
	}
	public void setSelected(boolean isSelected) {
		this.isSelected = isSelected;
	}
    
    //Gets and sets
    public String getName(){ return name; }
    public void setName(String newName){ name = newName; }
    public ArrayList<ObjectItem> getObjectItems(){ return objectItems; }
    public void setObjectItems(ArrayList<ObjectItem> objectItems) {	this.objectItems = objectItems;	}
    public int getPosX(){ return (int)getBoundsRectangle().getX(); }
    public int getPosY(){ return (int)getBoundsRectangle().getY(); }
   
}